/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "FusionStorageRestApiOperator.h"
#include <string>
#include <exception>
#include <algorithm>
#include "log/Log.h"
#include "common/Structs.h"
#include "common/Utils.h"
#include "common/utils/Utils.h"
#include "json/json.h"
#include "common/model/ResponseModel.h"
#include "client/FusionStorageRestClient.h"
#include "client/FusionStorageRestApiRequest.h"
#include "FusionStorageIscsiDiskScanner.h"
#include "config_reader/ConfigIniReaderImpl.h"

namespace {
const int32_t CONSTANT_NUM_10 = 10;
const int32_t RETRY_TIMES = 3;
const int32_t MAX_QUERY_TIMES = 5;
const int32_t RESCAN_WAIT_TIME = 30;
const int32_t HEX_START_POS = 2;
const int32_t QUERY_BITMAP_CREATING_INTERVAL = 10;
const int32_t WWN_START_POS = 4;
const int32_t NUM_FIVE = 5;
const std::string ERRCODE_VBS_COMMAND_ERR = "50510012";
const std::string ERRCODE_VOLUME_DONT_EXSIT = "50150005";
const int32_t NO_STORAGE_INFO = 1577213586;
const std::string ISCSI_SESSION_STATE_LOGGED_IN = "LOGGED IN";

using Defer = std::shared_ptr<void>;

const std::string EXTERNAL_BACKUP_SCENCE = "0";
const std::string INTERNAL_BACKUP_SCENCE = "1";
const std::string GET_TOKEN_URL = "https://{ip}:{port}/api/v2/aa/sessions";
const std::string GET_CURRENT_SESSION_URL = "https://{ip}:{port}/api/v2/aa/current_session";
const std::string GET_ISCSI_INITIATOR_URL = "https://{ip}:{port}/dsware/service/iscsi/queryPortInfo";
const std::string GET_HOST_LIST_URL = "https://{ip}:{port}/dsware/service/iscsi/queryAllHost";
const std::string QUERY_SNAPSHOT_URL = "https://{ip}:{port}/api/v2/block_service/snapshots";
const std::string QUERY_VOLUME_URL = "https://{ip}:{port}/api/v2/block_service/volumes";
const std::string QUERY_ISCSI_PORTAL_URL = "https://{ip}:{port}/dsware/service/cluster/dswareclient/queryIscsiPortal";
const std::string QUERY_HOST_FROM_VOLUME_URL = "https://{ip}:{port}/dsware/service/iscsi/queryHostFromVolume";
const std::string QUERY_ISCSI_SESSION_URL = "https://{ip}:{port}/api/v2/block_service/iscsi_sessions";
const std::string CREATE_HOST_URL = "https://{ip}:{port}/dsware/service/iscsi/createHost";
const std::string CREATE_INITIATOR_URL = "https://{ip}:{port}/dsware/service/iscsi/createPort";
const std::string ADD_INITIATOR_TO_HOST_URL = "https://{ip}:{port}/dsware/service/iscsi/addPortToHost";
const std::string ADD_LUN_TO_HOST_URL = "https://{ip}:{port}/dsware/service/iscsi/addLunsToHost";
const std::string DELETE_INITIATOR_URL = "https://{ip}:{port}/dsware/service/iscsi/deletePort";
const std::string DELETE_INITIATOR_FROM_HOST_URL = "https://{ip}:{port}/dsware/service/iscsi/deletePortFromHost";
const std::string DELETE_HOST_URL = "https://{ip}:{port}/dsware/service/${version}/host/delete";
const std::string DELETE_LUN_FROM_HOST_URL = "https://{ip}:{port}/dsware/service/iscsi/deleteLunFromHost";
const std::string CREATE_BITMAP_VOLUME_URL = "https://{ip}:{port}/api/v2/block_service/bitmap_volumes";
const std::string DELETE_BITMAP_VOLUME_URL = "https://{ip}:{port}/api/v2/block_service/volumes";
const std::string GET_VERSION_URL = "https://{ip}:{port}/dsware/service/cluster/version";
const std::string QUERY_BITMAP_VOLUME = "https://{ip}:{port}/api/v2/block_service/bitmap_volumes";
const std::string QUERY_HOST_OF_ISCSI_URL = "https://{ip}:{port}/dsware/service/iscsi/queryHostByPort";
const std::string QUERY_STORAGE_POOL =
    "https://{ip}:{port}/dsware/service/cluster/storagepool/queryStoragePool?poolid={id}";
}  // namespace

VIRT_PLUGIN_NAMESPACE_BEGIN

using ErrorCode = FusionStorageRestApiErrorCode;

FusionStorageRestApiOperator::FusionStorageRestApiOperator(
    const std::string &fusionstorMgrIp, const std::string &poolID, const std::string &jobId,
    const std::string &subJobId)
    : FusionStorageApi(fusionstorMgrIp, poolID), m_fusionStorageMgrIp(fusionstorMgrIp),
    m_jobId(jobId), m_subJobId(subJobId)
{
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_OK)] = "OK";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER)] =
        "The input parameters are incorrect.";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_LOGIN_TARGET_FAILED)] =
        "Failed to login the target ip";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_GET_WWN_FAILED)] =
        "The input parameters are incorrect.";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_CREATE_MAPPING_FAILED)] =
        "Failed to create mapping";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_GET_DISKPATH_FAILED)] =
        "Failed to get disk path by wwn.";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_INITIATOR_IS_NOT_EXIST)] =
        "The specified initiator does not exist";
    m_errorCodeToErrorDes[static_cast<int32_t>(ErrorCode::RESTAPI_ERR_UNKNOWN)] = "The unknown error";
}
FusionStorageRestApiOperator::FusionStorageRestApiOperator()
{}

FusionStorageRestApiOperator::~FusionStorageRestApiOperator()
{
    Module::CleanMemoryPwd(m_token);
}

int32_t FusionStorageRestApiOperator::GetStorageInfo(
    const std::string &authExtendInfo, const VolInfo &volInfo, bool &isBackUp)
{
    std::vector<StorageInfo> storageVector;
    if (!Utils::GetStoragesInfoFromExtendInfo(authExtendInfo, storageVector)) {
        ERRLOG("Failed to get storage info from extendinfo");
        return FAILED;
    }
    int32_t ret = GetControlDeviceInfo(storageVector, m_controlDeviceInfo, volInfo);
    if (ret != SUCCESS) {
        ERRLOG("Failed to get control deviceinfo");
        return ret;
    }

    m_isBackupJob = isBackUp;
    m_fusionStorageMgrPort = m_controlDeviceInfo.m_port;

    INFOLOG("Get storage info success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::GetControlDeviceInfo(
    std::vector<StorageInfo> &storageVector, ControlDeviceInfo &controlDeviceInfo, const VolInfo &volInfo)
{
    // 对接分布式存储时，在扩展信息里面的SN号就是IP
    for (auto &item : storageVector) {
        if (Utils::CheckVolIpInStorage(volInfo, item)) {
            controlDeviceInfo.m_ip = item.m_ip;
            Utils::GetIpVectorFromString(controlDeviceInfo.m_ipList, item.m_ip, item.m_ipList);
            controlDeviceInfo.m_port = std::to_string(item.m_port);
            controlDeviceInfo.m_userName = item.m_userName;
            controlDeviceInfo.m_password = item.m_passWd;
            controlDeviceInfo.m_storageType = item.m_storageType;
            std::string storageInfoStr;
            SetVbsNodeInfo(item);
            if (!Module::JsonHelper::StructToJsonString(item, storageInfoStr)) {
                ERRLOG("Convert storageInfo to json string failed.");
                return Module::FAILED;
            }
            CertManger storageCertMgr;
            CertInfo cert;
            if (!storageCertMgr.ParseCert(item.m_ip, storageInfoStr, cert)) {
                ERRLOG("Parse storage cert info failed.");
                return Module::FAILED;
            }
            if (controlDeviceInfo.m_enableCert) {
                controlDeviceInfo.m_cert = storageCertMgr.GetSpecifyCerPath(item.m_ip);
            }
            if (!item.m_revocationList.empty()) {
                controlDeviceInfo.m_revocationList = storageCertMgr.GetSpecifyRclPath(item.m_ip);
            }
            break;
        }
    }
    return controlDeviceInfo.m_ip != "" ? SUCCESS : NO_STORAGE_INFO;
}

void FusionStorageRestApiOperator::SetVbsNodeInfo(const StorageInfo& info)
{
    m_vbsNodeInfo.mNodeIp = info.m_vbsIp;
    m_vbsNodeInfo.mUserName = info.m_vbsUserName;
    m_vbsNodeInfo.mPort = info.m_vbsPort;
    m_vbsNodeInfo.mPassWord = info.m_vbsPassWord;
}

int32_t FusionStorageRestApiOperator::InitRestApiOperator()
{
    m_restClient = std::make_shared<FusionStorageRestClient>();
    if (m_restClient == nullptr) {
        ERRLOG("Failed to get rest client.");
        return FAILED;
    }

    std::string hostUUid;
    if (DiskScannerHandler::GetInstance()->GetHostSN(hostUUid) != SUCCESS) {
        ERRLOG("Failed to get host uuid.");
        return FAILED;
    }
    int npos = hostUUid.rfind("-");
    m_hostName = "Host" + hostUUid.substr(npos + 1);

    DBGLOG("Init rest api operator success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::TryGetToken()
{
    DBGLOG("Start try to get token.");

    if (GetCurrentSession() == SUCCESS) {
        DBGLOG("The current session exists, will use current token.");
        return SUCCESS;
    }
    WARNLOG("No current session exists, will get new token via restapi.");
    if (GetToken() != SUCCESS) {
        ERRLOG("Failed to get token, check the environment.");
        return FAILED;
    }

    DBGLOG("Get the new token via api success.");
    return SUCCESS;
}

// 用当前token查询连接信息
int32_t FusionStorageRestApiOperator::GetCurrentSession()
{
    RequestInfo requestInfo;
    InitRequestInfo(requestInfo, "GET", GET_CURRENT_SESSION_URL);
    requestInfo.m_headerParams["X-Auth-Token"] = GetFusionStorageToken();
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("Get current session failed, user is offine.");
            continue;
        }

        m_currentSessionInfo = response->GetBody();
        return SUCCESS;
    }
    return FAILED;
}

// 清理当前会话避免登录用户数上溢，接口中没有获得sessionid的操作，根据token清理会话
int32_t FusionStorageRestApiOperator::DeleteCurrentSession()
{
    INFOLOG("Start to delete current session.");

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer.");
        return FAILED;
    }
    RequestInfo requestInfo = FormatRequestInfo("DELETE", GET_TOKEN_URL);
    requestInfo.m_headerParams["X-Auth-Token"] = GetFusionStorageToken();
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("DELETE current session failed, please check the session status.");
            continue;
        }

        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::GetClientIp(const std::string &responseBody, std::string &responseResult)
{
    Json::Value responseJsonBody;
    Json::Reader reader;

    try {
        reader.parse(responseBody, responseJsonBody);
    } catch (const std::exception &e) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }

    if (!responseJsonBody.isObject() || !responseJsonBody.isMember("data") || !responseJsonBody["data"].isArray() ||
        responseJsonBody["data"].isNull()) {
        ERRLOG("The json response format is error, no result.");
        return FAILED;
    }
    if (!responseJsonBody["data"][0].isObject() || !responseJsonBody["data"][0].isMember("client_ip") ||
        !responseJsonBody["data"][0]["client_ip"].isString()) {
        ERRLOG("The json response format is error, no result.");
        return FAILED;
    }

    responseResult = responseJsonBody["data"][0]["client_ip"].asString();
    return SUCCESS;
}

// 获得token，每次都调用这个获得
int32_t FusionStorageRestApiOperator::GetToken()
{
    DBGLOG("Start to get token.");
    std::string errorDes;
    std::string responseBody;

    // 发送请求获得token
    if (GetTokenByAppEnv(responseBody, errorDes) != SUCCESS) {
        ERRLOG("Get token failed, error: %s.", errorDes.c_str());
        return FAILED;
    }
    if (DoGetToken(responseBody, m_token) != SUCCESS) {
        ERRLOG("Failed to get token from response body.");
        return FAILED;
    }

    DBGLOG("Get token success.");
    return SUCCESS;
}

// 从句柄中的环境信息获得账密，用账密发送session请求获得token
int32_t FusionStorageRestApiOperator::GetTokenByAppEnv(std::string &responseBody, std::string &errorDes)
{
    DBGLOG("Start to get token responseBody.");
    FusionStorageRestApiRequest request;
    RequestInfo requestInfo = GetTokenByAppEnvInner();

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer.");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            int32_t errorCode = result;
            ERRLOG("The user name or password is incorrect or the token reach the limit, errorCode %d", errorCode);
            continue;
        }
        responseBody = response->GetBody();
        DBGLOG("Get token response body success");
        return SUCCESS;
    }
    return FAILED;
}

RequestInfo FusionStorageRestApiOperator::GetTokenByAppEnvInner()
{
    RequestInfo requestInfo;
    requestInfo.m_method = "POST";
    requestInfo.m_resourcePath = GET_TOKEN_URL;
    requestInfo.m_pathParams["port"] = GetFusionStorageMgrPort();
    requestInfo.m_queryParams = {};
    requestInfo.m_headerParams["Content-Type"] = "application/json";

    Json::Value jsonReq;
    jsonReq["user_name"] = m_controlDeviceInfo.m_userName;
    jsonReq["password"] = m_controlDeviceInfo.m_password;
    jsonReq["scope"] = "0";
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    return requestInfo;
}

// 从响应体中执行解析，解析出的就是token
int32_t FusionStorageRestApiOperator::DoGetToken(const std::string &responseBody, std::string &token)
{
    Json::Value sessionResponseBody;
    Json::Reader reader;

    // 解析response
    if (!reader.parse(responseBody, sessionResponseBody)) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }
    if (!sessionResponseBody.isMember("data")) {
        ERRLOG("No data in the response.");
        return FAILED;
    }

    if (GetStringField(sessionResponseBody["data"], "x_auth_token", token)) {
        ERRLOG("Failed to parse x_auth_token.");
        return FAILED;
    }

    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::CreateBitmapVolume(const std::shared_ptr<RepositoryHandler> cacheRepoHandler,
    const std::string &filePath, BitmapVolumeInfo &info, std::string &errDes)
{
    if (CheckVbsNodeConnect() != SUCCESS) {
        if (!m_hasReportVbsConnectFailed) {
            std::vector<std::string> reportArgs = {m_vbsNodeInfo.mNodeIp};
            ReportJobDetailsParam reportPara = {
                "virtual_plugin_fusionstorage_volume_check_vbs_connect_failed_label",
                JobLogLevel::TASK_LOG_WARNING, SubJobStatus::RUNNING, 0, 0};
            Utils::ReportJobDetailWithLabel(reportPara, reportArgs, m_jobId, m_subJobId);
            m_hasReportVbsConnectFailed = true;
        }
        return FAILED;
    }
    if (DoCreateBitmapVol(info, errDes) != SUCCESS) {
        ERRLOG("Create bitmap volume %s failed.", info.volName.c_str());
        return FAILED;
    }
    std::string infoStr;
    Module::JsonHelper::StructToJsonString(info, infoStr);
    if (Utils::SaveToFileWithRetry(cacheRepoHandler, filePath, infoStr) != SUCCESS) {
        ERRLOG("Save bitmap volume %s info to %s failed.", info.volName.c_str(), filePath.c_str());
        return FAILED;
    }
    INFOLOG("Save bitmap volume %s info to %s success.", info.volName.c_str(), filePath.c_str());
    if (RetryToQueryBitmap(info) != SUCCESS) {
        ERRLOG("RetryToQueryBitmap failed.");
        return FAILED;
    }
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::RetryToQueryBitmap(BitmapVolumeInfo &info)
{
    int32_t failedTime = 0;
    int32_t maxTime = Module::ConfigReader::getInt(
        std::string("HcsConfig"), std::string("CreateBitmapVolumeTimeOut"));
    auto startTime = std::chrono::steady_clock::now();
    maxTime = std::max(maxTime, info.createTimeOut);
    INFOLOG("CreateBitmapVolume timeout is %d.", maxTime);
    while (true) {
        if ((uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() -
            startTime).count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den) >
            maxTime) {
            ERRLOG("Waiting CreateBitmapVolume result timeout, timeOut: %d.", maxTime);
            return FAILED;
        }
        BitmapVolumeInfo temp;
        temp.volName = info.volName;
        std::string errStr;
        if (QueryBitmapVol(temp, errStr) != static_cast<int32_t>(ErrorCode::RESTAPI_OK)) {
            ERRLOG("Query bitmap volume failed.");
            failedTime++;
            if (failedTime <= MAX_QUERY_TIMES) {
                std::this_thread::sleep_for(std::chrono::seconds(QUERY_BITMAP_CREATING_INTERVAL));
                continue;
            }
            ERRLOG("Querry bitmap volume failed %d times.", failedTime);
            return FAILED;
        }
 
        failedTime = 0;
        DBGLOG("Bitmap volume create status:[%d].", temp.status);
        if (temp.status == 0) {
            INFOLOG("Create bitmap volume %s success.", info.volName.c_str());
            return SUCCESS;
        }
 
        if (temp.status != static_cast<uint32_t>(FusionStoraeVolumeStatus::CREATING)) {
            ERRLOG("Volume status is :[%d].", temp.status);
            return FAILED;
        }
 
        std::this_thread::sleep_for(std::chrono::seconds(QUERY_BITMAP_CREATING_INTERVAL));
    }
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::DoCreateBitmapVol(BitmapVolumeInfo &info, std::string &errDes)
{
    INFOLOG("Start to create bitmap volume, volume name: %s, snap name from %s, snap name to %s.",
        info.volName.c_str(), info.snapNameFrom.c_str(), info.snapNameTo.c_str());
    RequestInfo requestInfo = FormatRequestInfo("POST", CREATE_BITMAP_VOLUME_URL);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Null response pointer.");
        return FAILED;
    }
    Json::Value jsonReq;
    jsonReq["vol_name_for_bitmap"] = info.volName;
    // 全备时，没有起始快照，只传终止快照
    if (!info.snapNameFrom.empty()) {
        jsonReq["snap_name_from"] = info.snapNameFrom;
    }
    jsonReq["snap_name_to"] = info.snapNameTo;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result != RESTAPISUCCESS) {
            ERRLOG("Create bitmap volume failed, err: %s.", response->GetBody().c_str());
            break;
        }
        FusionStorageResponse<CreateBitmapResponse> volResponse;
        if (!Module::JsonHelper::JsonStringToStruct(response->GetBody(), volResponse)) {
            ERRLOG("Failed to convert res Body to CreateBitmapResponse.");
            return FAILED;
        }
        // 分布式接口有问题，这几个size填错了
        info.snapSize = volResponse.mData.mSnapSize;
        info.blockSize = volResponse.mData.mBitmapSize;
        info.volSize = volResponse.mData.mSnapSize;
        INFOLOG("Send create bitmap volume request success.");
        return SUCCESS;
    }
    ERRLOG("Create bitmap volume %s failed.", info.volName.c_str());
    return FAILED;
}
 
int32_t FusionStorageRestApiOperator::DeleteBitmapVolume(const std::string &bitmapVolumeName, std::string &errDes)
{
    if (m_vbsNodeInfo.mNodeIp.empty()) {
        INFOLOG("No vbs node info cant delete bitmap volume.");
        return FAILED;
    }
    INFOLOG("Start to delete bitmap volume, volume name: %s.", bitmapVolumeName.c_str());
    LoginHost cmdExcuter;
    SshParam sshInfo(m_vbsNodeInfo);
    sshInfo.mCommand = "sudo /bin/vbs_cli -c deletevolume -v " + bitmapVolumeName;
    std::string resultStr = "";
    if (cmdExcuter.RunCmd(sshInfo, resultStr) != SUCCESS || resultStr.find("success") == std::string::npos) {
        ERRLOG("Delete bitmap %s failed.", bitmapVolumeName.c_str());
        return FAILED;
    }
    INFOLOG("Delete bitmap %s success.", bitmapVolumeName.c_str());
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::DoDeleteBitmapVolume(const std::string &volumeName, std::string &errDes)
{
    RequestInfo requestInfo = FormatRequestInfo("DELETE", DELETE_BITMAP_VOLUME_URL);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Null response pointer.");
        return FAILED;
    }
    Json::Value jsonReq;
    jsonReq["name"] = volumeName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("Delete bitmap volume %s failed.", volumeName.c_str());
            continue;
        }
        return SUCCESS;
    }
    INFOLOG("Delete bitmap volume %s success.", volumeName.c_str());
    return SUCCESS;
}
 
int32_t FusionStorageRestApiOperator::GetVersion(int32_t &version, std::string &errDes)
{
    RequestInfo request = FormatRequestInfo("GET", GET_VERSION_URL);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Null response pointer.");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        request.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(request, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("Get system version info ailed.");
            continue;
        }
        VersionInfo versionInfo;
        if (!Module::JsonHelper::JsonStringToStruct(response->GetBody(), versionInfo)) {
            ERRLOG("Failed to convert res Body to VersionInfo.");
            return FAILED;
        }
        INFOLOG("System version is %s.", versionInfo.mVersion.c_str());
        std::vector<std::string> versionArr;
        version = 0;
        boost::split(versionArr, versionInfo.mVersion, boost::is_any_of("."));
        for (const auto &it : versionArr) {
            version = version * CONSTANT_NUM_10 + Module::SafeStoi(it);
        }
        return SUCCESS;
    }
}

// 挂载卷：创建启动器和主机，启动器添加到主机，建立lun和主机映射，通过扫盘获得设备文件指针。
int32_t FusionStorageRestApiOperator::AttachVolume(
    const std::string &volumeName, std::string &diskDevicePath, std::string &errorDes)
{
    INFOLOG("Start to attach volume, volume name: %s, m_fusionStorageMgrIP: %s.",
        volumeName.c_str(),
        m_fusionStorageMgrIp.c_str());

    // 通过查询存储得到目标卷的WWN，用于之后扫盘和验证
    if (GetVolumeWwnByName(volumeName, errorDes) != SUCCESS) {
        int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_GET_DISKPATH_FAILED);
        errorDes = GetErrString(errorCode);
        ERRLOG("Get wwn via api failed.");
        return FAILED;
    }
    // 建立ISCSI连接、增加启动器到主机上、将卷映射到主机上，删除映射行为的成功失败不影响程序逻辑。
    int32_t ret = CreateHostLunMapping(m_hostName, volumeName, errorDes);
    if (ret != SUCCESS) {
        int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_CREATE_MAPPING_FAILED);
        errorDes = GetErrString(errorCode);
        ERRLOG("Create mapping failed, can not attach the target lun: %s", volumeName.c_str());
        DeleteHostLunMapping(m_hostName, volumeName, errorDes);
        return FAILED;
    }
    // 扫盘，获得设备路径，挂载路径自动建立，没得到就失败，同时删除才创建的映射
    INFOLOG("The params of do scan disk is [volumeName: %s], [wwn: %s].", volumeName.c_str(), m_volumeWwn.c_str());
    ret = DoScanDisk(volumeName, m_volumeWwn, diskDevicePath);
    if (ret != SUCCESS) {
        int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_GET_DISKPATH_FAILED);
        errorDes = GetErrString(errorCode);
        ERRLOG("Scan disk failed, volumeName: %s, volumeWwn: %s", volumeName.c_str(), m_volumeWwn.c_str());
        DeleteHostLunMapping(m_hostName, volumeName, errorDes);
        return FAILED;
    }

    m_curDiskDevicePath = diskDevicePath;
    INFOLOG("Attach volume: %s successfully, its path is %s.", volumeName.c_str(), diskDevicePath.c_str());
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::AttachBitmapVolume(
    const std::string &bitmapVolumeName, std::string &diskDevicePath, std::string &errorDes)
{
    INFOLOG("Start to attach bitmap volume, volume name: %s, m_fusionStorageMgrIP: %s.",
        bitmapVolumeName.c_str(), m_fusionStorageMgrIp.c_str());
    LoginHost cmdExcuter;
    SshParam sshInfo(m_vbsNodeInfo);
    sshInfo.mCommand = "sudo sh /opt/dsware/vbs/script/vbs/vbs_cmd.sh 14 1504 " + bitmapVolumeName;
    std::string resultStr = "";
    cmdExcuter.RunCmd(sshInfo, resultStr);
    int pos = resultStr.find("WWN:");
    if (pos == std::string::npos) {
        ERRLOG("Query bitmap volume %s wwn failed.", bitmapVolumeName.c_str());
        return FAILED;
    }
    int tailPos = resultStr.find("\n", pos);
    m_bitmapWwn = resultStr.substr(pos + WWN_START_POS, tailPos - pos - NUM_FIVE);
    INFOLOG("Bitmap volume : %s , wwn : %s.", bitmapVolumeName.c_str(), m_bitmapWwn.c_str());
 
    // 建立ISCSI连接、增加启动器到主机上、将卷映射到主机上，删除映射行为的成功失败不影响程序逻辑。
    int32_t ret = CreateHostLunMapping(m_hostName, bitmapVolumeName, errorDes);
    if (ret != SUCCESS) {
        int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_CREATE_MAPPING_FAILED);
        errorDes = GetErrString(errorCode);
        ERRLOG("Create mapping failed, can not attach the bitmap volume: %s", bitmapVolumeName.c_str());
        DeleteHostLunMapping(m_hostName, bitmapVolumeName, errorDes);
        return FAILED;
    }
    // 扫盘，获得设备路径，挂载路径自动建立，没得到就失败，同时删除才创建的映射
    INFOLOG("The params of do scan disk is [volumeName: %s], [wwn: %s].", bitmapVolumeName.c_str(),
        m_bitmapWwn.c_str());
    ret = DoScanDisk(bitmapVolumeName, m_bitmapWwn, diskDevicePath);
    if (ret != SUCCESS) {
        int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_GET_DISKPATH_FAILED);
        errorDes = GetErrString(errorCode);
        ERRLOG("Scan disk failed, volumeName: %s, volumeWwn: %s", bitmapVolumeName.c_str(), m_bitmapWwn.c_str());
        DeleteHostLunMapping(m_hostName, bitmapVolumeName, errorDes);
        return FAILED;
    }
    INFOLOG("Attach bitmap volume %s success, device path : %s.", bitmapVolumeName.c_str(), diskDevicePath.c_str());\
    return SUCCESS;
}
 

// 建立ICSSI连接1：检查并登录目标器
int32_t FusionStorageRestApiOperator::CheckIscsiTarget(const std::string &hostName, std::string &errorDes,
    bool &needLogin)
{
    INFOLOG("Start to check and login target iscsi portal.");
    std::string responseBody;

    // 查询相关ISCSI端口信息
    int32_t ret = QueryIscsiPortal(responseBody, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Query iscsi portal failed, error: %s", errorDes.c_str());
        return FAILED;
    }
    // 获得端口列表，目标端口将会保存在成员变量m_iscsiPortalInfo中
    ret = GetTargetIscsiPortal(responseBody, m_targetIscsiPortalList, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Parse iscsi port list failed, error: %s", errorDes.c_str());
        return FAILED;
    }
    // 检查可用端口列表和已登录端口是否有交集
    ret = CheckExistLoginedTarget(m_targetIscsiPortalList);
    if (ret != SUCCESS) {
        INFOLOG("Need login a new target.");
        needLogin = true;
    }
    return SUCCESS;
}

// 查询iscsiPortal，通过这个获得相应的iscsi服务端口信息
int32_t FusionStorageRestApiOperator::QueryIscsiPortal(std::string &responseBody, std::string &errorDes)
{
    DBGLOG("Start to query iscsi Portal.");

    RequestInfo requestInfo = FormatRequestInfo("POST", QUERY_ISCSI_PORTAL_URL);
    FusionStorageRestApiRequest request;
    Json::Value jsonReq;
    Json::FastWriter fastWriter;
    requestInfo.m_body = "{}";

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }

    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Failed to query iscsi poratal information, the error is %s.", errorDes.c_str());
            continue;
        }

        responseBody = response->GetBody();
        DBGLOG("Query iscsi portal success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::GetTargetIscsiPortal(
    const std::string &responseBody, std::vector<Json::Value> &targetIscsiPortalList, std::string &errorDes)
{
    DBGLOG("Start to get target iscsi portal.");
    Json::Value responseJsonBody;
    Json::Reader reader;
    int32_t responseResult;

    try {
        reader.parse(responseBody, responseJsonBody);
    } catch (const std::exception &e) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }

    if (!responseJsonBody.isObject() || !responseJsonBody.isMember("nodeResultList") ||
        !responseJsonBody["nodeResultList"].isArray()) {
        ERRLOG("The json response format is error, no result.");
        return FAILED;
    }

    bool isFind = false;
    Json::Value nodeResultList = responseJsonBody["nodeResultList"];
    for (int i = 0; i < nodeResultList.size(); ++i) {
        Json::Value nodeResult = nodeResultList[i];
        if (nodeResult.isObject() && nodeResult.isMember("iscsiPortalList") &&
            nodeResult["iscsiPortalList"].isArray()) {
            Json::Value iscsiPortalList = nodeResult["iscsiPortalList"];
            if (GetTargetIscsiPortalInner(iscsiPortalList) == SUCCESS) {
                targetIscsiPortalList.push_back(nodeResult);
                isFind = true;
            }
        }
    }

    if (isFind) {
        INFOLOG("Parse node result list success.");
        return SUCCESS;
    } else {
        ERRLOG("Parse node result list failed, unknown error.");
        return FAILED;
    }
}

int32_t FusionStorageRestApiOperator::GetTargetIscsiPortalInner(Json::Value &iscsiPortalList)
{
    if (!iscsiPortalList.isArray()) {
        ERRLOG("The iscsi portal list is not array.");
        return FAILED;
    }
    for (int j = 0; j < iscsiPortalList.size(); ++j) {
        Json::Value iscsiPortal = iscsiPortalList[j];
        if (iscsiPortal.isObject() && iscsiPortal.isMember("iscsiStatus") && iscsiPortal["iscsiStatus"].isString() &&
            iscsiPortal["iscsiStatus"].asString() == "active") {
            if (iscsiPortal.isMember("iscsiPortal") && iscsiPortal["iscsiPortal"].isString() &&
                iscsiPortal.isMember("targetName") && iscsiPortal["targetName"].isString()) {
                return SUCCESS;
            }
        }
    }

    ERRLOG("Failed to get target iscsi portal in inner operation.");
    return FAILED;
}

// 检查是否有已存在的登录的IP
int32_t FusionStorageRestApiOperator::CheckExistLoginedTarget(std::vector<Json::Value> &targetIscsiPortalList)
{
    DBGLOG("Start to check target in login ip.");
    std::vector<IscsiSessionStatus> sessionStatusList;
    DiskScannerHandler::GetInstance()->GetIscsiSessionStatus(sessionStatusList);
    // 判断活跃端口中是否有已登录IP
    for (auto &targetPortal : targetIscsiPortalList) {
        std::string targetPortalIp;
        if (!targetPortal["iscsiPortalList"].isNull()) {
            GetStringField(targetPortal["iscsiPortalList"][0], "iscsiPortal", targetPortalIp);
            int32_t colonPos = targetPortalIp.find(':');
            if (colonPos != std::string::npos) {
                targetPortalIp = targetPortalIp.substr(0, colonPos);
            }
            int32_t loginFlag = CheckContain(targetPortalIp, sessionStatusList);
            if (loginFlag != FAILED) {
                DBGLOG("The environment has one target ip has been logined, ip: %s", targetPortalIp.c_str());
                return SUCCESS;
            }
        }
    }

    WARNLOG("New target ip needed to login!");
    return FAILED;
}

// 检查并登录目标器2：登录目标器
int32_t FusionStorageRestApiOperator::LoginTarget()
{
    INFOLOG("Start to login the target.");
    for (auto &targetPortal : m_targetIscsiPortalList) {
        std::string targetPortalIp;
        GetStringField(targetPortal["iscsiPortalList"][0], "iscsiPortal", targetPortalIp);
        int32_t colonPos = targetPortalIp.find(':');
        if (colonPos != std::string::npos) {
            targetPortalIp = targetPortalIp.substr(0, colonPos);
        }

        if (CheckLoginedTarget(targetPortalIp) == SUCCESS) {
            INFOLOG("The target has logined.");
            return SUCCESS;
        }
        if (DoLoginTarget(targetPortalIp) == SUCCESS) {
            INFOLOG("Do login target iscsi portal success.");
            return SUCCESS;
        }
    }

    ERRLOG("Failed to login the target, please check the environment.");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DoLoginTarget(const std::string &targetPortalIp)
{
    INFOLOG("Start to do login target iscsi portal, the target portalip is: %s.", targetPortalIp.c_str());
    // 执行登录操作
    if (DiskScannerHandler::GetInstance()->LoginIscsiTarget(targetPortalIp) == SUCCESS) {
        WARNLOG("Login iscsi target success, target ip:%s", targetPortalIp.c_str());
        return SUCCESS;
    }
    // 检查登录的Target是否已经被登录上。
    if (CheckLoginedTarget(targetPortalIp) != SUCCESS) {
        ERRLOG("Failed to login the target.");
        return FAILED;
    }

    INFOLOG("Login iscsi target success, target ip:%s", targetPortalIp.c_str());
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::CheckLoginedTarget(const std::string &aimTarget)
{
    std::vector<IscsiSessionStatus> sessionStatusList;
    DiskScannerHandler::GetInstance()->GetIscsiSessionStatus(sessionStatusList);

    int32_t loginFlag = CheckContain(aimTarget, sessionStatusList);
    if (loginFlag != FAILED) {
        INFOLOG("Target ip has logined, ip: %s", aimTarget.c_str());
        return SUCCESS;
    }

    WARNLOG("New target ip needed to login!");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::CheckContain(const std::string &strTarget,
    std::vector<IscsiSessionStatus> &loginedSessions)
{
    for (std::vector<IscsiSessionStatus>::iterator iter = loginedSessions.begin();
        loginedSessions.end() != iter; ++iter) {
        if (strTarget == iter->m_targetIp && iter->m_sessionStatus == ISCSI_SESSION_STATE_LOGGED_IN) {
            DBGLOG("The target ip has been logined in this host successfully.");
            m_iscsiIqnName = iter->m_localIqn;
            return SUCCESS;
        }
    }
    DBGLOG("The target ip has not been login in this host.");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::CreateHostLunMapping(
    const std::string &hostName, const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Start to create host:%s-lun:%s mapping.", hostName.c_str(), volumeName.c_str());

    // 检查映射状态，已有映射就返回成功
    int32_t ret = QueryHostLunMapping(hostName, volumeName, errorDes);
    if (ret == SUCCESS) {
        INFOLOG("The host - lun mapping exists.");
        return SUCCESS;
    }
    // 登录目标器、添加主机、启动器、增加启动器到主机
    ret = CreateIscsiInitiatorAndHost(hostName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Create iscsi initiator and host failed, error: %s", errorDes.c_str());
        return FAILED;
    }
    // 将卷映射到主机上
    ret = AddLunToHost(hostName, volumeName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Add lun to host failed error: %s.", errorDes.c_str());
        return FAILED;
    }
    // 再次检查映射状态
    ret = QueryHostLunMapping(hostName, volumeName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("The host - lun mapping has not been created, error: %s.", errorDes.c_str());
        return FAILED;
    }

    INFOLOG("Create host-lun mapping success.");
    return SUCCESS;
}

// 主机-LUN 建立映射关系2：建立ISCSI连接
int32_t FusionStorageRestApiOperator::CreateIscsiInitiatorAndHost(const std::string &hostName, std::string &errorDes)
{
    INFOLOG("Start to create iscsi initiator and host.");
    // 检查目标器是否已登录
    bool needLogin = false;
    if (CheckIscsiTarget(hostName, errorDes, needLogin) != SUCCESS) {
        ERRLOG("Check iscsi target failed.");
        return FAILED;
    }
    // 检查并增加启动器
    std::string iqnNumber;
    Defer _(nullptr, [&](...) { Module::CleanMemoryPwd(iqnNumber); });
    int32_t ret = CheckAndCreateIscsiInitiator(hostName, iqnNumber, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to check and create iscsi initiator, error: %s.", errorDes.c_str());
        return FAILED;
    }

    if (needLogin && LoginTarget() != SUCCESS) {
        ERRLOG("Login the target failed");
        return FAILED;
    }
    INFOLOG("Create iscsi initiator and host success.");
    return SUCCESS;
}

// 在Restapi里面的portName 就是 iqnnumber
int32_t FusionStorageRestApiOperator::CheckAndCreateIscsiInitiator(
    const std::string &hostName, std::string &portName, std::string &errorDes)
{
    INFOLOG("Start to check and create iscsi initiator.");
    // 通过命令获得当前主机启动器IQN
    if (!m_iscsiIqnName.empty()) {
        portName = m_iscsiIqnName;
    } else if (DiskScannerHandler::GetInstance()->GetIscsiInitor(portName) != SUCCESS) {
        ERRLOG("Get iscsi initiator iqn failed!");
        return FAILED;
    }
    // 查询存储上的启动器，没得到就创建
    int32_t ret = GetIscsiInitiatorByName(portName, errorDes);
    if (ret != SUCCESS) {
        WARNLOG("Get iscsi initiatror failed, error: %s.", errorDes.c_str());
        ret = CreateIscsiInitiator(portName, errorDes);
        if (ret != SUCCESS) {
            ERRLOG("Get and create iscsi initiator both failed, error: %s.", errorDes.c_str());
            return ret;
        }
    }
    // 查询主机，没得到就创建
    ret = GetHostByName(hostName, errorDes);
    if (ret != SUCCESS) {
        WARNLOG("Get host by name failed, error: %s.", errorDes.c_str());
        ret = CreateHost(hostName, errorDes);
        if (ret != SUCCESS) {
            ERRLOG("Get and create host both failed, the errorDes is %s.", errorDes.c_str());
            return ret;
        }
    }
    ret = MapIscsiToHost(portName, hostName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to map iscsi initiator to host, error: %s.", errorDes.c_str());
        return ret;
    }
    ret = QueryIscsiSession(hostName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to get the iscsi session of this host, error: %s.", errorDes.c_str());
        return ret;
    }

    INFOLOG("Check and create iscsi initiator success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::MapIscsiToHost(const std::string &portName, const std::string &hostName,
    std::string &errorDes)
{
    std::vector<std::string> hosts;
    int32_t ret = QueryHostIscsiMapped(portName, hosts, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("QueryHostIscsiMapped failed, error: %s.", errorDes.c_str());
        return ret;
    }
    bool mapToRightHost = false;
    for (const auto &host : hosts) {
        if (host == hostName) {
            mapToRightHost = true;
            INFOLOG("IscsiInitiator has mapped to host:%s.", hostName.c_str());
            continue;
        }
        WARNLOG("IscsiInitiator mapped to host:%s , need delete mapping.", host.c_str());
        DeleteIscsiInitiatorFromHost(host, portName, errorDes);
    }
    if (!mapToRightHost) {
        ret = AddIscsiInitiatorToHost(hostName, portName, errorDes);
        if (ret != SUCCESS) {
            ERRLOG("Add iscssi initiator to host failed, error: %s.", errorDes.c_str());
            return ret;
        }
    }
    INFOLOG("MapIscsiToHost success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::QueryHostIscsiMapped(const std::string &portName,
    std::vector<std::string> &mappedHosts, std::string &errorDes)
{
    INFOLOG("Start to query host that iscsi(iqn:%s) mapped.", portName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", QUERY_HOST_OF_ISCSI_URL);
    Json::Value jsonReq;
    Json::Value portArray;
    portArray.append(portName);
    jsonReq["portName"] = portArray;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            int32_t errorCode = result;
            errorDes = GetErrString(errorCode);
            ERRLOG("Failed to query HostIscsiMapped, the errorCode %d errorDes %s.", errorCode, errorDes.c_str());
            continue;
        }
        if (ParseMapResult(response->GetBody(), portName, mappedHosts) != SUCCESS) {
            ERRLOG("Parse mapped result failed.");
            return FAILED;
        }
        INFOLOG("QueryHostIscsiMapped success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::ParseMapResult(const std::string &responseBody, const std::string &iscsiIqn,
    std::vector<std::string> &mappedHosts)
{
    Json::Value responseJsonBody;
    Json::Reader reader;
    int32_t responseResult;

    if (!reader.parse(responseBody, responseJsonBody)) {
        ERRLOG("The json reader failed to read the response body, response body: %s.",
            WIPE_SENSITIVE(responseBody.c_str()));
        return FAILED;
    }
    if (!responseJsonBody.isMember("portHostMap")) {
        ERRLOG("The json response format is error, response body: %s.", WIPE_SENSITIVE(responseBody.c_str()));
        return FAILED;
    }
    Json::Value mapResult = responseJsonBody["portHostMap"];
    if (!mapResult.isMember(iscsiIqn)) {
        INFOLOG("IscsiInitiator dont map to any host.");
        return SUCCESS;
    }
    Json::Value hostArray = mapResult[iscsiIqn];
    for (int index = 0; index < hostArray.size(); ++index) {
        std::string hostName = hostArray[index].asString();
        mappedHosts.push_back(hostName);
    }
    INFOLOG("Parse mapped result success.");
    return SUCCESS;
}

// 检查主机的ISCSI连接，已有返回0
int32_t FusionStorageRestApiOperator::QueryIscsiSession(const std::string &hostName, std::string &errorDes)
{
    INFOLOG("Start to query iscsi session.");

    RequestInfo requestInfo = FormatRequestInfo("GET", QUERY_ISCSI_SESSION_URL);
    requestInfo.m_queryParams["host_name"] = hostName;

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            int32_t errorCode = result;
            errorDes = GetErrString(errorCode);
            INFOLOG("Failed get the iscsi session, the errorCode %d errorDes %s.", errorCode, errorDes.c_str());
            continue;
        }

        DBGLOG("Find the host has iscsi session in the fusionstorage.");
        return SUCCESS;
    }
    return FAILED;
}

// 解除映射关系
int32_t FusionStorageRestApiOperator::DeleteHostLunMapping(
    const std::string &hostName, const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Start to delete mapping between lun: %s, and host %s.", volumeName.c_str(), hostName.c_str());

    // 检查映射状态，非0表示映射不存在，不存在就返回成功
    int32_t ret = QueryHostLunMapping(hostName, volumeName, errorDes);
    if (ret != SUCCESS) {
        INFOLOG("Find no mapping between %s and %s.", hostName.c_str(), volumeName.c_str());
        return SUCCESS;
    }
    // 执行删除映射
    ret = DeleteLunFromHost(hostName, volumeName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to do delete host - lun mapping action, errorDes: %s.", errorDes.c_str());
        return FAILED;
    }
    // 检查映射状态，如果没有就表示删除成功了
    ret = QueryHostLunMapping(hostName, volumeName, errorDes);
    if (ret == SUCCESS) {
        ERRLOG("Query host - lun mapping failed, error: %s.", errorDes.c_str());
        return FAILED;
    }

    INFOLOG("Delete host-lun mapping success.");
    return SUCCESS;
}

// 挂载卷2：扫盘获得文件信息
int32_t FusionStorageRestApiOperator::DoScanDisk(
    const std::string &volumeName, const std::string &volumeWwn, std::string &diskDevicePath)
{
    INFOLOG(
        "Start to do scan disk, target volumeName is %s, and its wwn is %s.", volumeName.c_str(), volumeWwn.c_str());

    // 0x6888603000002d46fa168449642ec40b --> 6888603000002d46fa168449642ec40b
    std::string matchVolumeWwn = volumeWwn;
    matchVolumeWwn = volumeWwn.substr(HEX_START_POS);
    INFOLOG("The matchVolumeWwn is %s.", matchVolumeWwn.c_str());

    std::string depolyScence = EXTERNAL_BACKUP_SCENCE;
    if (Utils::GetAgentDeployScence(depolyScence) != SUCCESS) {
        ERRLOG("Failed to get the depoly scence, will enter the external scence.");
    }
    m_isInternalScence = (depolyScence == INTERNAL_BACKUP_SCENCE);

    int retryTimes = 0;
    while (retryTimes < RETRY_TIMES) {
        int32_t ret = FusionStorageIscsiDiskScanner::GetInstance()->DoScanAfterMapped(
            volumeName, matchVolumeWwn, diskDevicePath, m_isInternalScence);
        if (ret != FAILED && !diskDevicePath.empty()) {
            INFOLOG("Get the disk path from wwn success, the diskDevicePath is %s.", diskDevicePath.c_str());
            m_diskPathSet[volumeName] = diskDevicePath;
            return SUCCESS;
        } else {
            ERRLOG("Failed to get disk path from wwn, wait for retry three times or exit.");
        }

        WARNLOG("Retry to scan disk, retry times:%d, wwn:%s", retryTimes, matchVolumeWwn.c_str());
        ++retryTimes;
        std::this_thread::sleep_for(std::chrono::seconds(RESCAN_WAIT_TIME));
    }

    ERRLOG("Failed to do scan disk, retry times over.");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DetachVolume(const std::string &volumeName, std::string &errorDes)
{
    INFOLOG(
        "Start to detach volume, volume name: %s, dswareMgr IP: %s.", volumeName.c_str(), m_fusionStorageMgrIp.c_str());
    // 解除卷和所有主机的映射关系
    int32_t ret = DeleteVolumeAllMapping(volumeName, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to delete volume all mapping.");
        return FAILED;
    }
    // 从路径集合中删除，不删除将一直留存，直到target logout
    if (m_diskPathSet.find(volumeName) == m_diskPathSet.end()) {
        INFOLOG("Volume %s is not in disk path set, no need to delete path.", volumeName.c_str());
        return SUCCESS;
    }
    std::string targetPath = m_diskPathSet[volumeName];
    ret = FusionStorageIscsiDiskScanner::GetInstance()->DeleteDiskFromPathSet(volumeName, targetPath);
    if (ret != SUCCESS) {
        ERRLOG("Delete iscsi disk from path set failed.");
        return FAILED;
    }
    m_diskPathSet.erase(volumeName);
    INFOLOG("Detach volume success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::DeleteVolumeAllMapping(const std::string &volume, std::string &errorDes)
{
    std::vector<std::string> hostNameList;
    int32_t ret = GetVolumeMappedHost(volume, hostNameList, errorDes);
    if (errorDes == ERRCODE_VOLUME_DONT_EXSIT) {
        INFOLOG("Delete volume %s mapping success.", volume.c_str());
        return SUCCESS;
    }
    if (ret != SUCCESS) {
        ERRLOG("Failed to get volume attached host.");
        return FAILED;
    }
    // 循环解除所有映射，解除失败忽略。
    for (int i = 0; i < hostNameList.size(); i++) {
        DeleteHostLunMapping(hostNameList[i], volume, errorDes);
    }
    // 再次查询卷的映射情况
    hostNameList.clear();
    ret = GetVolumeMappedHost(volume, hostNameList, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to get volume attached host.");
        return FAILED;
    }
    if (!hostNameList.empty()) {
        ERRLOG("Failed to delete volume all mapping.");
        return FAILED;
    }
    INFOLOG("Delete volume %s all mapping success.", volume.c_str());
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::GetVolumeMappedHost(
    const std::string &volumeName, std::vector<std::string> &hostNameList, std::string &errorDes)
{
    // 查询卷映射的主机信息
    std::string responseBody;
    int32_t ret = QueryHostFromVolume(volumeName, responseBody, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to query host from volume, error: %s", errorDes.c_str());
        return FAILED;
    }
    ret = ParseMappedHostList(responseBody, hostNameList);
    if (ret != SUCCESS) {
        ERRLOG("Failed to parse mapped host list from responsebody.");
        return FAILED;
    }

    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::ParseMappedHostList(
    const std::string &responseBody, std::vector<std::string> &hostNameList)
{
    Json::Value hostQueryInfo;
    Json::Reader reader;
    if (!reader.parse(responseBody, hostQueryInfo)) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }
    if (!hostQueryInfo.isObject() || !hostQueryInfo.isMember("hostList") || !hostQueryInfo["hostList"].isArray()) {
        ERRLOG("No hostList in the response.");
        return FAILED;
    }
    // 获得卷列表
    Json::Value hostList = hostQueryInfo["hostList"];
    for (int i = 0; i < hostList.size(); i++) {
        Json::Value hostInfo = hostList[i];
        std::string mappedHostName;
        GetStringField(hostInfo, "hostName", mappedHostName);
        hostNameList.push_back(mappedHostName);
    }

    return SUCCESS;
}

// 在备份和恢复中均不会执行该操作，实现仅为保证可以使用它进行健康检查
int32_t FusionStorageRestApiOperator::QueryBitmapVol(BitmapVolumeInfo &info, std::string &errorDes)
{
    RequestInfo requestInfo = FormatRequestInfo("GET", QUERY_BITMAP_VOLUME);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Null response pointer.");
        return FAILED;
    }
    Json::Value jsonReq;
    jsonReq["vol_name"] = info.volName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("Query bitmap volume failed.");
            continue;
        }
        FusionStorageResponse<FusionStorageVolume> volResponse;
        if (!Module::JsonHelper::JsonStringToStruct(response->GetBody(), volResponse)) {
            ERRLOG("Failed to convert res Body to FusionStorageResponse.");
            return FAILED;
        }
        info.status = volResponse.mData.mStatus;
 
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::GetIscsiInitiatorByName(const std::string &portName, std::string &errorDes)
{
    INFOLOG("Start query iscsi initiator");

    RequestInfo requestInfo = FormatRequestInfo("POST", GET_ISCSI_INITIATOR_URL);
    Json::Value jsonReq;
    jsonReq["portName"] = portName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Query iscsi initiator failed, error: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_INITIATOR_IS_NOT_EXIST);
            errorDes = GetErrString(errorCode);
            ERRLOG("Query iscsi initiator failed, error: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }

        INFOLOG("Get iscsi initiator by name success");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::CreateIscsiInitiator(const std::string &portName, std::string &errorDes)
{
    INFOLOG("Start create iscsi port: %s", portName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", CREATE_INITIATOR_URL);
    Json::Value jsonReq;
    jsonReq["portName"] = portName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Create iscsi port failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        // 如果在创建启动器时发现已经创建了，打印WARN日志，逻辑上视为成功
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_OK);
            errorDes = GetErrString(errorCode);
            WARNLOG("Create iscsi port failed, already created, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            return SUCCESS;
        }

        INFOLOG("Create iscsi initiator success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DeleteIscsiInitiator(const std::string &portName, std::string &errorDes)
{
    INFOLOG("Start to delete iscsi port ");

    RequestInfo requestInfo = FormatRequestInfo("POST", DELETE_INITIATOR_URL);
    Json::Value jsonReq;
    jsonReq["portName"] = portName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Create iscsi initiator failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_UNKNOWN);
            errorDes = GetErrString(errorCode);
            WARNLOG("Create iscsi initiator failed, already created, errorCode: %d, des: %s",
                errorCode, errorDes.c_str());
            return SUCCESS;
        }
        INFOLOG("Delete the iscsi initiator success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::AddIscsiInitiatorToHost(
    const std::string &hostName, const std::string &portName, std::string &errorDes)
{
    INFOLOG("Start bind iscsi initiator to host: %s", hostName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", ADD_INITIATOR_TO_HOST_URL);
    Json::Value jsonReq;
    Json::Value jsonPortName;
    jsonReq["hostName"] = hostName;
    jsonReq["portNames"][0] = portName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Add iscsi initiator to host failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        // 当已经创建了启动器时，逻辑上视为成功，打印DBG日志
        if (result == RESTAPIWRONGACION) {
            WARNLOG("Add iscsi initiator to host failed, already created.");
            return SUCCESS;
        }
        INFOLOG("Add iscsi initiator to host success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DeleteIscsiInitiatorFromHost(
    const std::string &hostName, const std::string &portName, std::string &errorDes)
{
    INFOLOG("Start delete iscsi initiator: %s from host: %s", portName.c_str(), hostName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", DELETE_INITIATOR_FROM_HOST_URL);
    Json::Value jsonReq;
    jsonReq["hostName"] = hostName;
    jsonReq["portNames"][0] = portName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Delete iscsi from host failed, error: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_OK);
            errorDes = GetErrString(errorCode);
            WARNLOG("Delete iscsi initiator from host failed, error: %d, des: %s", errorCode, errorDes.c_str());
            return SUCCESS;
        }

        INFOLOG("Delete iscsi initiator from host success.");
        return SUCCESS;
    }
    return FAILED;
}

// 创建主机
int32_t FusionStorageRestApiOperator::CreateHost(const std::string &hostName, std::string &errorDes)
{
    INFOLOG("Create host: %s", hostName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", CREATE_HOST_URL);
    Json::Value jsonReq;
    jsonReq["hostName"] = hostName;
    std::string clientIp;
    if (GetClientIp(m_currentSessionInfo, clientIp) == SUCCESS) {
        INFOLOG("Get the client ip success.");
        jsonReq["ipAddress"] = clientIp;
    }
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to get result from response.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            WARNLOG("Create host failed, error: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }

        INFOLOG("Create the host success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DeleteHost(const std::string &hostName, std::string &errorDes)
{
    INFOLOG("Start to delete host: %s", hostName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", DELETE_HOST_URL);
    Json::Value jsonReq;
    jsonReq["hostName"] = hostName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != RESTAPISUCCESS) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Delete host failed, error: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }

        INFOLOG("Delete host by name success.");
        return SUCCESS;
    }
    return FAILED;
}

// 查询卷/快照有映射关系的主机，将获得的responseBody传回
int32_t FusionStorageRestApiOperator::QueryHostFromVolume(
    const std::string &volumeName, std::string &responseBody, std::string &errorDes)
{
    INFOLOG("Query host from volume: %s ", volumeName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", QUERY_HOST_FROM_VOLUME_URL);
    Json::Value jsonReq;
    jsonReq["lunName"] = volumeName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (response->GetBody().find(ERRCODE_VOLUME_DONT_EXSIT) != std::string::npos) {
            errorDes = ERRCODE_VOLUME_DONT_EXSIT;
            WARNLOG("Volume %s dont exist.", volumeName.c_str());
            return FAILED;
        }
        if (result != RESTAPISUCCESS) {
            ERRLOG("Query host from volume failed, errorDes: %s", response->GetBody().c_str());
            continue;
        }

        responseBody = response->GetBody();
        INFOLOG("Query host from volume name success");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::AddLunToHost(
    const std::string &hostName, const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Start add lun %s to host %s", volumeName.c_str(), hostName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", ADD_LUN_TO_HOST_URL);
    Json::Value jsonReq;
    jsonReq["hostName"] = hostName;
    jsonReq["lunNames"][0] = volumeName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Add lun to host failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        // 如果在增加LUN时发现已经建立映射了，打印DBG日志，逻辑上视为成功
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            WARNLOG("Add lun to host failed, already added, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            return SUCCESS;
        }
        INFOLOG("Add lun to host success.");
        return SUCCESS;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::DeleteLunFromHost(
    const std::string &hostName, const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Start to do delete mapping action between host: %s and volume: %s.", hostName.c_str(), volumeName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("POST", DELETE_LUN_FROM_HOST_URL);
    Json::Value jsonReq;
    jsonReq["hostName"] = hostName;
    jsonReq["lunNames"][0] = volumeName;
    Json::FastWriter fastWriter;
    requestInfo.m_body = fastWriter.write(jsonReq);

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            WARNLOG("Failed to delete the host-lun mapping, maybe deleted before or the host/volume not exist.");
        } else {
            INFOLOG("Do delete the host-lun mapping success.");
            return SUCCESS;
        }

        continue;
    }
    return FAILED;
}

// 通过查询卷名的信息获得wwn，用于获取磁盘路径和校验挂载的卷是否正确
int32_t FusionStorageRestApiOperator::GetVolumeWwnByName(const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Get the wwn of volume by name: %s.", volumeName.c_str());
    std::string responseBody;

    if (m_isBackupJob) {
        int32_t ret = QuerySnapshotInfoByName(volumeName, responseBody, errorDes);
        if (ret != static_cast<int32_t>(ErrorCode::RESTAPI_OK)) {
            ERRLOG("Failed to get volume info by snapshot name.");
            return FAILED;
        }
        INFOLOG("Query snapshot information by name success.");
    } else {
        int32_t ret = QueryVolumeInfoByName(volumeName, responseBody, errorDes);
        if (ret != static_cast<int32_t>(ErrorCode::RESTAPI_OK)) {
            ERRLOG("Failed to get volume info by volume name.");
            return FAILED;
        }
        INFOLOG("Query volume information by name success.");
    }
    int32_t ret = GetSnapshotOrVolumeInfo(responseBody, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to get volume Info from reponse body.");
        return FAILED;
    }

    INFOLOG("The volume wwn is: %s.", m_volumeWwn.c_str());
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::GetSnapshotOrVolumeInfo(const std::string &responseBody, std::string &errorDes)
{
    INFOLOG("Start to get wwn from response body.");
    Json::Value QueryInfo;
    Json::Reader reader;

    try {
        reader.parse(responseBody, QueryInfo);
    } catch (const std::exception &e) {
        errorDes = "The json reader failed to read the response body.";
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }
    if (!QueryInfo.isObject() || !QueryInfo.isMember("data")) {
        errorDes = "No data in the response.";
        ERRLOG("No data in the response body.");
        return FAILED;
    }

    GetStringField(QueryInfo["data"], "wwn", m_volumeWwn);
    INFOLOG("Get the snapshot information from the response body success.");
    return SUCCESS;
}

// 查询快照信息
int32_t FusionStorageRestApiOperator::QuerySnapshotInfoByName(
    const std::string &snapshotName, std::string &responseBody, std::string &errorDes)
{
    DBGLOG("Query snapshot info by name: %s ", snapshotName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("GET", QUERY_SNAPSHOT_URL);
    requestInfo.m_queryParams["name"] = snapshotName;

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Query snapshot by name failed, errorCode: %d, des: %s.", errorCode, errorDes.c_str());
            continue;
        }

        responseBody = response->GetBody();
        DBGLOG("Query snapshot info by name success.");
        return result;
    }
    return FAILED;
}

// -- 该接口较老式 -- 查询卷信息，尺寸、WWN都在这里获得
int32_t FusionStorageRestApiOperator::QueryVolumeInfoByName(
    const std::string &volumeName, std::string &responseBody, std::string &errorDes)
{
    INFOLOG("Query volume info by name: %s ", volumeName.c_str());

    RequestInfo requestInfo = FormatRequestInfo("GET", QUERY_VOLUME_URL);
    requestInfo.m_queryParams["name"] = volumeName;

    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, true);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result != SUCCESS) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Query volume by name failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }

        responseBody = response->GetBody();
        INFOLOG("Query volume by name success.");
        return result;
    }
    return FAILED;
}

int32_t FusionStorageRestApiOperator::QueryHostLunMapping(
    const std::string &hostName, const std::string &volumeName, std::string &errorDes)
{
    INFOLOG("Start to query host-lun mapping of [host: %s], [volumeName: %s].", hostName.c_str(), volumeName.c_str());
    std::string responseBody;

    // 获得主机列表
    int32_t ret = QueryHostFromVolume(volumeName, responseBody, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Failed to query host from volume, error: %s", errorDes.c_str());
        return FAILED;
    }
    // 检查卷挂载的主机列表中是否有该主机名
    ret = CheckHostInList(responseBody, hostName);
    if (ret != SUCCESS) {
        ERRLOG("The host is not in the host list");
        return FAILED;
    }

    INFOLOG("Query host-lun mapping success, the mapping exists.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::GetHostByName(const std::string &hostName, std::string &errorDes)
{
    INFOLOG("Start to get host by name, the host is: %s.", hostName.c_str());
    std::string queryAllhost;

    // 请求查询主机列表，获得包含主机列表的响应
    int32_t ret = GetHostList(queryAllhost, errorDes);
    if (ret != SUCCESS) {
        ERRLOG("Query all host failed, error: %s.", errorDes.c_str());
        return FAILED;
    }
    // 在主机列表中寻找主机对象
    ret = CheckHostInList(queryAllhost, hostName);
    if (ret != SUCCESS) {
        ERRLOG("The host not in the system, error: %s.", errorDes.c_str());
        return FAILED;
    }

    INFOLOG("Get host by name success, the host exsits.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::GetHostList(std::string &hostList, std::string &errorDes)
{
    INFOLOG("Start query host list");

    RequestInfo requestInfo = FormatRequestInfo("GET", GET_HOST_LIST_URL);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        if (result == RESTAPIFAILED) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_WRONG_REQUEST_PARAMETER);
            errorDes = GetErrString(errorCode);
            ERRLOG("Get host list failed, errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }
        if (result == RESTAPIWRONGACION) {
            int32_t errorCode = static_cast<int32_t>(ErrorCode::RESTAPI_ERR_UNKNOWN);
            errorDes = GetErrString(errorCode);
            DBGLOG("Get host list failed, host errorCode: %d, des: %s", errorCode, errorDes.c_str());
            continue;
        }

        hostList = response->GetBody();
        DBGLOG("Get host list success.");
        return SUCCESS;
    }
    return FAILED;
}

// 检查主机列表中是否有目标机，有就返回OK
int32_t FusionStorageRestApiOperator::CheckHostInList(
    const std::string &hostQueryResponseBody, const std::string &hostName)
{
    DBGLOG("Start to check host in host list.");
    Json::Value hostQueryInfo;
    Json::Reader reader;

    if (!reader.parse(hostQueryResponseBody, hostQueryInfo)) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }
    if (!hostQueryInfo.isMember("hostList")) {
        ERRLOG("No hostList in the response.");
        return FAILED;
    }

    Json::Value hostList = hostQueryInfo["hostList"];
    for (int i = 0; i < hostList.size(); i++) {
        Json::Value hostInfo = hostList[i];
        std::string checkHostName;
        GetStringField(hostInfo, "hostName", checkHostName);
        if (checkHostName == hostName) {
            DBGLOG("Find the host in the list.");
            return SUCCESS;
        }
    }

    ERRLOG("Failed to find the host in the list.");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::GetResponseResult(const std::string &responseBody, bool codeFlag)
{
    Json::Value responseJsonBody;
    Json::Reader reader;
    int32_t responseResult;

    if (!reader.parse(responseBody, responseJsonBody)) {
        ERRLOG("The json reader failed to read the response body.");
        return FAILED;
    }
    if (!responseJsonBody.isMember("result")) {
        ERRLOG("The json response format is error.");
        return FAILED;
    }

    if (!codeFlag) {
        if (GetIntField(responseJsonBody, "result", responseResult) == SUCCESS) {
            return responseResult;
        }
    } else {
        if (GetIntField(responseJsonBody["result"], "code", responseResult) == SUCCESS) {
            return responseResult;
        }
    }
    return FAILED;
}

std::string FusionStorageRestApiOperator::GetErrString(const int32_t &errorCode)
{
    std::map<int, std::string>::iterator it = m_errorCodeToErrorDes.find(errorCode);
    if (it != m_errorCodeToErrorDes.end()) {
        return it->second;
    } else {
        return "Unknown error.";
    }
}

int32_t FusionStorageRestApiOperator::GetStringField(Json::Value &json, const string &field, std::string &result)
{
    if (json.isMember(field) && json[field].isString()) {
        result = json[field].asString();
        return SUCCESS;
    }
    ERRLOG("Failed to get string field.");
    return FAILED;
}

int32_t FusionStorageRestApiOperator::GetIntField(Json::Value &jsonBody, const string &field, int32_t &result)
{
    if (jsonBody.isMember(field) && jsonBody[field].isInt()) {
        result = jsonBody[field].asInt();
        return SUCCESS;
    }
    ERRLOG("Failed to get int field from json.");
    return FAILED;
}

RequestInfo FusionStorageRestApiOperator::FormatRequestInfo(
    const std::string requestMethod, const std::string resourcePath)
{
    RequestInfo requestInfo;
    InitRequestInfo(requestInfo, requestMethod, resourcePath);
    // 如果没有正常拿到token就让X-Auth-Token置空
    int32_t ret = TryGetToken();
    if (ret != SUCCESS) {
        INFOLOG("Failed to get the token correctly, set it to null.");
        Module::CleanMemoryPwd(m_token);
    } else {
        requestInfo.m_headerParams["X-Auth-Token"] = m_token;
    }

    INFOLOG("Success to format requestInfo.");
    return requestInfo;
}

void FusionStorageRestApiOperator::InitRequestInfo(RequestInfo &requestInfo,
    const std::string requestMethod, const std::string resourcePath)
{
    requestInfo.m_method = requestMethod;
    requestInfo.m_resourcePath = resourcePath;
    requestInfo.m_pathParams["port"] = GetFusionStorageMgrPort();
    requestInfo.m_queryParams = {};
    // 证书及吊销列表
    requestInfo.m_auth.certVerifyEnable = m_controlDeviceInfo.m_enableCert ? Module::CACertVerification::VCENTER_VERIFY
            : Module::CACertVerification::DO_NOT_VERIFY;
    requestInfo.m_auth.cert = m_controlDeviceInfo.m_cert;
    requestInfo.m_auth.revocationList = m_controlDeviceInfo.m_revocationList;
}

int32_t FusionStorageRestApiOperator::checkResponseResult(
    RequestInfo &requestInfo, std::shared_ptr<ResponseModel> response, bool errorType)
{
    FusionStorageRestApiRequest request;
    if (m_restClient->CallApi(requestInfo, response, request, m_isOpService) != SUCCESS) {
        ERRLOG("Failed to send request, http status: %u", response->GetHttpStatusCode());
        return FAILED;
    }
    int32_t result = GetResponseResult(response->GetBody(), errorType);
    if (result == FAILED) {
        ERRLOG("Failed to get result from response.");
        return FAILED;
    }
    return result;
}

int32_t FusionStorageRestApiOperator::CheckVbsNodeConnect()
{
    if (m_vbsNodeInfo.mNodeIp.empty()) {
        INFOLOG("There is no vbs node info, no need to check connect.");
        return SUCCESS;
    }
    LoginHost cmdExcuter;
    SshParam sshInfo;
    sshInfo.mIp = m_vbsNodeInfo.mNodeIp;
    sshInfo.mUserName = m_vbsNodeInfo.mUserName;
    sshInfo.mPort = m_vbsNodeInfo.mPort;
    sshInfo.mPassWord = m_vbsNodeInfo.mPassWord;
    sshInfo.mCommand = "sudo /bin/vbs_cli";
    std::string resultStr = "";
    if (cmdExcuter.RunCmd(sshInfo, resultStr) != SUCCESS ||
        resultStr.find(ERRCODE_VBS_COMMAND_ERR) == std::string::npos) {
        ERRLOG("User %s exec command /bin/vbs_cli failed, result: %s.", sshInfo.mUserName.c_str(), resultStr.c_str());
        return FAILED;
    }
    INFOLOG("Check vbs connect success.");
    return SUCCESS;
}

int32_t FusionStorageRestApiOperator::QueryStoragePoolUsedRate(double &usedCapacityRate)
{
    INFOLOG("Start to query storage pool %s infomation.", GetPoolID().c_str());
    RequestInfo requestInfo = FormatRequestInfo("GET", QUERY_STORAGE_POOL);
    std::shared_ptr<ResponseModel> response = std::make_shared<ResponseModel>();
    if (response == nullptr) {
        ERRLOG("Failed to get response pointer");
        return FAILED;
    }
    for (const std::string &ip : m_controlDeviceInfo.m_ipList) {
        requestInfo.m_pathParams["ip"] = ip;
        requestInfo.m_pathParams["id"] = GetPoolID();
        int32_t result = checkResponseResult(requestInfo, response, false);
        if (result == FAILED) {
            ERRLOG("Failed to call rest api.");
            continue;
        }
        std::string errorDes;
        if (result != SUCCESS) {
            int32_t errorCode = result;
            errorDes = GetErrString(errorCode);
            ERRLOG("Failed to query StoragePool, the errorCode %d errorDes %s.", errorCode, errorDes.c_str());
            continue;
        }
        StoragePools storagePoolsInfo;
        if (!Module::JsonHelper::JsonStringToStruct(response->GetBody(), storagePoolsInfo)) {
            ERRLOG("Failed to convert res Body to StoragePools, resBody: %s.",
                WIPE_SENSITIVE(response->GetBody().c_str()));
            return FAILED;
        }
        if (storagePoolsInfo.mStoragePools.size() != 1) {
            ERRLOG("Querieded storage pools number is not 1, but %d.", storagePoolsInfo.mStoragePools.size());
            return FAILED;
        }
        INFOLOG("Query storage pool %s info success, totalCapacity %ld, usedCapacity %ld, usedCapacityRate %f.",
            GetPoolID().c_str(), storagePoolsInfo.mStoragePools[0].mTotalCapacity,
            storagePoolsInfo.mStoragePools[0].mUsedCapacity, storagePoolsInfo.mStoragePools[0].mUsedCapacityRate);
        usedCapacityRate = storagePoolsInfo.mStoragePools[0].mUsedCapacityRate;
        return SUCCESS;
    }
    return FAILED;
}

std::string FusionStorageRestApiOperator::GetFusionStorageMgrIp()
{
    return m_fusionStorageMgrIp;
}

std::string FusionStorageRestApiOperator::GetFusionStorageMgrPort()
{
    return m_fusionStorageMgrPort;
}

std::string FusionStorageRestApiOperator::GetHostName()
{
    return m_hostName;
}

std::string FusionStorageRestApiOperator::GetFusionStorageToken()
{
    return m_token;
}

std::string FusionStorageRestApiOperator::GetCurDiskDevicePath()
{
    return m_curDiskDevicePath;
}

void FusionStorageRestApiOperator::SetFusionStorageMgrIp(const std::string &mgrIp)
{
    m_fusionStorageMgrIp = mgrIp;
}

void FusionStorageRestApiOperator::SetFusionStorageMgrPort(const std::string &mgrPort)
{
    m_fusionStorageMgrPort = mgrPort;
}

void FusionStorageRestApiOperator::SetHostName(const std::string &hostName)
{
    m_hostName = hostName;
}

void FusionStorageRestApiOperator::SetFusionStorageToken(const std::string &token)
{
    m_token = token;
}

bool FusionStorageRestApiOperator::GetIsInternalScence()
{
    return m_isInternalScence;
}

VIRT_PLUGIN_NAMESPACE_END